﻿using System;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;

namespace Neoseeker.NAMFox.Tests.Browsers
{
    /// <summary>
    /// Specifies which browser this test assembly should target.
    /// </summary>
    [AttributeUsage(AttributeTargets.Assembly)]
    public sealed class TargetBrowserAttribute : Attribute
    {
        private TargetBrowser browser;

        /// <summary>
        /// Initializes a new instance of the <see cref="TargetBrowserAttribute"/> class.
        /// </summary>
        /// <param name="browser">The browser against which to run the tests.</param>
        public TargetBrowserAttribute(TargetBrowser browser)
        {
            this.browser = browser;
        }

        /// <summary>
        /// Gets the browser against which tests are being run.
        /// </summary>
        public TargetBrowser TargetBrowser
        {
            get { return this.browser; }
        }

        /// <summary>
        /// Loads the configuration information for the browser of choice.
        /// </summary>
        /// <returns>A <see cref="BrowserConfiguration"/> object, which provides
        /// information about how to run tests against the particular browser.</returns>
        public BrowserConfiguration LoadBrowserConfiguration()
        {
            // We do some convention-based lookups to find the appropriate BrowserConfiguration
            // object for a given TargetBrowser. Since TargetBrowser values are of the
            // form [BrowserName][Version], we can first split them into their constituent parts...
            var components = Regex.Match(this.browser.ToString(), @"^(?<BrowserName>[^\d]+)(?<Version>\d[\s\S]*)$");
            string browserName = components.Groups["BrowserName"].Value;
            string version = components.Groups["Version"].Value.Replace('_', '.');

            // Now we look for a type in the assembly whose name is [BrowserName]Configuration e.g.
            // FirefoxConfiguration
            string desiredTypeName = browserName + "Configuration";
            Type browserConfigurationType = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsSubclassOf(typeof(BrowserConfiguration)) && t.Name == desiredTypeName).SingleOrDefault();

            if (browserConfigurationType == null)
            {
                throw new InvalidOperationException("Could not find a BrowserLocator-derived class that can find the browser of choice. Looking for " + desiredTypeName);
            }

            // Once we successfully find that type, we'll create a new instance of
            // it and assume that the constructor takes one parameter (the Version).
            return (BrowserConfiguration)Activator.CreateInstance(browserConfigurationType, new Version(version));
        }
    }
}
